package com.cy.springcloudalibaba.services.impls;

import com.cy.springcloudalibaba.mappers.AccountMapper;
import com.cy.springcloudalibaba.models.Account;
import com.cy.springcloudalibaba.services.AccountService;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

/**
 * @Description: 账户
 * @ClassName: AccountServiceImpl
 * @Author: chenyu
 * @Date: 2025/2/6 10:56
 */
@Slf4j
@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountMapper accountMapper;

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW) //开启新事务
    public void reduceBalance(Integer userId, BigDecimal price) throws Exception {
        log.info("[reduceBalance] 当前 XID：{}", RootContext.getXID());

        //检查余额
        log.info("[checkBalance] 检查用户 {} 余额", userId);
        Account account = accountMapper.selectAccountByUserId(userId);
        if (account.getBalance().doubleValue() < price.doubleValue()) {
            log.info("[checkBalance] 用户 {} 余额不足，当前余额：{}", userId, account.getBalance().doubleValue());
            throw new Exception("余额不足");
        }
        log.info("[reduceBalance] 开始扣减用户 {} 余额", userId);
        //扣除余额
        int updateCount = accountMapper.reduceBalance(userId, price);

        if (updateCount == 0) {
            log.warn("[reduceBalance] 扣除用户 {} 余额失败", userId);
            throw new Exception("余额不足");
        }
        log.info("[reduceBalance] 扣除用户 {} 余额成功", userId);
    }

    /**
     * tcc服务（confirm）方法
     * @author chenyu
     * @param context 上下文
     * @return boolean
     * @date 2025/2/7 10:14
     */
    @Override
    public boolean commitTcc(BusinessActionContext context) {
        log.info("Confirm阶段，AccountServiceImpl，commitTcc --> xid = " + context.getXid() +
                "，commitTcc提交成功");
        return true;
    }

    /**
     * tcc服务（cancel）方法
     * @author chenyu
     * @param context 上下文
     * @return boolean
     * @date 2025/2/7 10:14
     */
    @Override
    public boolean cancelTcc(BusinessActionContext context) {
        log.info("Cancel阶段，AccountServiceImpl，cancelTcc --> xid = " + context.getXid() +
                "，cancelTcc提交失败");
        //TODO 这里可以实现中间件，非关系型数据库的回滚
        //进行数据库回滚
        Integer userId = (Integer) context.getActionContext("userId");
        BigDecimal price = (BigDecimal) context.getActionContext("price");

        //TODO 需要考虑幂等性问题，多线程下可能会多加
        accountMapper.increaseBalance(userId, price);

        return true;
    }
}
